package com.demomaster.quickaccessibility.service;

import static android.view.View.GONE;
import static android.view.View.VISIBLE;

import android.graphics.Rect;
import android.text.TextUtils;
import android.util.Log;
import android.view.accessibility.AccessibilityNodeInfo;

import androidx.annotation.IntDef;
import androidx.annotation.NonNull;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class AccessNodeFinder {
    private static String TAG = AccessNodeFinder.class.getSimpleName();
    static AccessNodeFinder instance;

    public static AccessNodeFinder getInstance() {
        if (instance == null) {
            instance = new AccessNodeFinder();
        }
        return instance;
    }


    private AccessNodeFinder() {

    }

    public static List<AccessibilityNodeInfo> findOneByBuilder(FindBuilder findBuilder) {
        if (findBuilder != null && QuickAccessibilityService.instance != null) {
            int screenWidth = QuickAccessibilityService.instance.screenWidth;
            int screenHeight = QuickAccessibilityService.instance.screenHeight;
            screenRect = new Rect(0, 0, screenWidth, screenHeight);
            AccessibilityNodeInfo rootNode = findBuilder.anchorNodeInfo == null ? QuickAccessibilityService.instance.getRootInActiveWindow() : findBuilder.anchorNodeInfo;

            if (rootNode != null) {
                if (!TextUtils.isEmpty(findBuilder.id)) {//id使用精准匹配
                    List<AccessibilityNodeInfo> accessibilityNodeInfoList = rootNode.findAccessibilityNodeInfosByViewId(findBuilder.id);
                    //Log.i("accessibilityNodeInfoList","accessibilityNodeInfoList.size="+accessibilityNodeInfoList.size());
                    if (accessibilityNodeInfoList != null && accessibilityNodeInfoList.size() > 0) {
                        List<AccessibilityNodeInfo> list = new ArrayList<>();
                        for (AccessibilityNodeInfo nodeInfo : accessibilityNodeInfoList) {
                            if (isNodeMatch(nodeInfo, findBuilder)) {
                                list.add(nodeInfo);
                                if (!findBuilder.isList) {
                                    return list;
                                }
                            } else {
                                Log.d("AccessNodeFinder", "isNodeMatch false,nodeInfo=" + nodeInfo);
                            }
                        }
                        return list;
                    }
                    return null;
                }

                if (!TextUtils.isEmpty(findBuilder.text_equals)) {
                    List<AccessibilityNodeInfo> nodeInfoList = rootNode.findAccessibilityNodeInfosByText(findBuilder.text_equals);//有些视图无法被查询到比如isVisibleToUser不可见的
                    //Log.d(TAG, "findAccessibilityNodeInfosByText=" + (nodeInfoList==null?"null":nodeInfoList.size()));
                    if (nodeInfoList != null && nodeInfoList.size() > 0) {
                        List<AccessibilityNodeInfo> list = new ArrayList<>();
                        for (AccessibilityNodeInfo nodeInfo : nodeInfoList) {
                            try {
                                FindBuilder findBuilder1 = (FindBuilder) findBuilder.clone();
                                findBuilder1.setText_equals(null);//这里已经查询过文本了，后续不用在查找文本
                                if (isNodeMatch(nodeInfo, findBuilder1)) {
                                    list.add(nodeInfo);
                                    if (!findBuilder.isList) {
                                        return list;
                                    }
                                }
                            } catch (CloneNotSupportedException e) {
                                throw new RuntimeException(e);
                            }
                        }
                        if (list.size() > 0) {
                            return list;
                        }
                    }
                }
//                if(!TextUtils.isEmpty(findBuilder.text_regex)){
//                    if(containsOnlyOrRelation(findBuilder.text_regex)){
//
//                    }
//                }

                //处理搜索区域 根据条件中的findBuilder.fromNodeInfo查找子类
                //List<AccessibilityNodeInfo> nodeInfoList = QuickAccessibilityService.instance.getRootInActiveWindow();
//                if (findBuilder.anchorNodeInfo != null) {
////                    if (findBuilder.matchingInSub) {//匹配子节点
////                        nodeInfoList = getAllChildNode(new ArrayList<>(), findBuilder.anchorNodeInfo);// covertToMap(findBuilder.anchorNodeInfo);
////                    } else {//匹配父节点
////                        nodeInfoList = getAllChildNode(new ArrayList<>(), findBuilder.anchorNodeInfo.getParent());// covertToMap(findBuilder.anchorNodeInfo.getParent());
////                    }
//                } else {
//                    if(findBuilder.inScreenType==ScreenPosition.IN_SCREEN){//获取可见的节点列表
//                        Log.d("AccessNodeFinder","i获取可见的节点列表");
//                        nodeInfoList = AccessNodeCache.getInstance().getVisiableNodeList();
////                        Rect rect1 = new Rect(0, 0, QuickAccessibilityService.instance.screenWidth, QuickAccessibilityService.instance.screenHeight);
////                        Rect rect2 = new Rect();//// QuickAccessibilityHelper.getBundsInScreen(nodeInfo);
////                        nodeInfo.getBoundsInScreen(rect2);
////                        if (!rect1.intersect(rect2)) {//剔除掉非屏幕范围外的节点
////                            continue W;
////                        }
//                    }else {//获取全部的节点列表
//                        nodeInfoList = AccessNodeCache.getInstance().getNodeList();
//                    }
//                    //currentNodeInfoMap = AccessNodeFinder.getInstance().getAccessNodeMap();
//                }
                /******************/

                if (findBuilder.depthMatch || !TextUtils.isEmpty(findBuilder.text_regex)) {
                    //创建一个队列，用于存储待遍历的节点
                    Queue<AccessibilityNodeInfo> queue = new LinkedList<>();
                    queue.offer(rootNode);
                    //循环遍历队列中的节点
                    while (!queue.isEmpty()) {
                        //从队列中取出一个节点
                        AccessibilityNodeInfo nodeInfo = queue.poll();
                        if (nodeInfo != null) {
                            boolean isInScreen = true;
                            boolean isMatch = true;

                            if (findBuilder.inScreenType == ScreenPosition.IN_SCREEN) {
                                isInScreen = isInScreen(nodeInfo);
                                if (!isInScreen) {
                                    isMatch = false;
                                    if (!TextUtils.isEmpty(findBuilder.text_equals) && findBuilder.text_equals.equals(nodeInfo.getText())) {
                                        Log.d("AccessNodeFinder", "不在屏幕内=" + nodeInfo);
                                    }
                                }
                            }
                            //findBuilder.setInScreenType(ScreenPosition.NO_LIMIT);
                            if (isMatch && isNodeMatch(nodeInfo, findBuilder)) {
                                List<AccessibilityNodeInfo> list = new ArrayList<>();
                                list.add(nodeInfo);
                                return list;
                            } else {
                                if (isInScreen) {
                                    // 将当前节点的所有子节点添加到队列中
                                    int count = nodeInfo.getChildCount();
                                    for (int i = 0; i < count; i++) {
                                        queue.offer(nodeInfo.getChild(i));
                                    }
                                }
                            }
                        }
                    }
                }
                /******************/

            }
        }
        return null;
    }

    // 提取检查节点是否在屏幕内的方法
    private static boolean isInScreen(AccessibilityNodeInfo nodeInfo) {
        Rect rect2 = AccessibilityHelper.getBundsInScreen(nodeInfo);
        return screenRect != null && rect2 != null && screenRect.intersect(rect2);
    }

    static Rect screenRect;//屏幕范围

    /**
     * 检查给定的正则表达式是否只包含“或”关系。
     *
     * @param regex 给定的正则表达式
     * @return 如果正则表达式只包含“或”关系，则返回 true；否则返回 false
     */
    public static boolean containsOnlyOrRelation(String regex) {
        // 移除正则表达式中的空白字符
        String trimmedRegex = regex.replaceAll("\\s", "");

        // 检查除了或关系（'|'）之外是否还有其他字符
        // 我们使用一个正则表达式来查找除了或关系（'|'）之外的任何字符
        String nonOrPattern = "[^|]";

        Pattern pattern = Pattern.compile(nonOrPattern);
        Matcher matcher = pattern.matcher(trimmedRegex);

        // 如果找到了除了或关系（'|'）之外的任何字符，则返回 false
        return !matcher.find();
    }

    // 提取检查节点是否匹配指定条件的方法
    private static boolean isNodeMatch(AccessibilityNodeInfo nodeInfo, FindBuilder findBuilder) {
        //if(screenRect==null) {
        screenRect = new Rect(0, 0, QuickAccessibilityService.instance.screenWidth, QuickAccessibilityService.instance.screenHeight);
        //}
        // 检查节点是否在屏幕内
        if (findBuilder.inScreenType == ScreenPosition.IN_SCREEN) {
            if (!isInScreen(nodeInfo)) {
                Rect rect = new Rect();
                nodeInfo.getBoundsInScreen(rect);
                Log.e("AccessNodeFinder", "不在屏幕内 hash=" + nodeInfo.hashCode() + "," + nodeInfo + ",screenRect=" + screenRect + ",reat=-" + rect);
                return false;
            }
        }
        // 检查文本是否为空
        if (!TextUtils.isEmpty(findBuilder.text_equals) || !TextUtils.isEmpty(findBuilder.text_regex)) {
            if (TextUtils.isEmpty(nodeInfo.getText())) {
                //Log.e("AccessNodeFinder", "文字为空不匹配=" + nodeInfo);
                return false;
            }
        }
        // 检查可见性
        if (findBuilder.visible != -1) {
            if ((nodeInfo.isVisibleToUser() ? 0 : 8) != findBuilder.visible) {
                //Log.e("AccessNodeFinder", "显示状态不匹配=" + nodeInfo);
                return false;
            }
        }
        // 检查可点击性
        if (findBuilder.clickable != -1) {
            if ((nodeInfo.isClickable() ? 1 : 0) != findBuilder.clickable) {
                //Log.e("AccessNodeFinder", "点击状态不匹配=" + nodeInfo);
                return false;
            }
        }

        // 检查内容描述
        if (!TextUtils.isEmpty(findBuilder.contentDescription)) {
            CharSequence contentDesc = nodeInfo.getContentDescription();
            if (TextUtils.isEmpty(contentDesc)) {
                return false;
            } else {
                Pattern pattern = Pattern.compile(findBuilder.contentDescription);
                Matcher matcher = pattern.matcher(contentDesc);
                if (!matcher.find()) {
                    //Log.e("AccessNodeFinder", "描述不匹配=" + nodeInfo);
                    return false;
                }
            }
        }
        // 检查视图类名
        if (!TextUtils.isEmpty(findBuilder.viewClassName)) {
            if (!findBuilder.viewClassName.equals(nodeInfo.getClassName())) {
                //Log.e("AccessNodeFinder", "控件类型不匹配=" + nodeInfo);
                return false;
            }
        }
        // 检查视图 ID
        if (!TextUtils.isEmpty(findBuilder.id)) {
            if (!findBuilder.id.equals(nodeInfo.getViewIdResourceName())) {
                //Log.e("AccessNodeFinder", "过滤资源id=" + nodeInfo);
                return false;
            }
        }
        // 检查文本正则表达式
        if (!TextUtils.isEmpty(findBuilder.text_regex)) {
            Pattern pattern = Pattern.compile(findBuilder.text_regex);
            Matcher matcher = pattern.matcher(nodeInfo.getText());
            if (!matcher.find()) {
                return false;
            }
        }
        // 检查文本等于
        if (!TextUtils.isEmpty(findBuilder.text_equals)) {
            if (!findBuilder.text_equals.equals(nodeInfo.getText())) {
                return false;
            }
        }

        return true;
    }

    /*private static Map<Integer, AccessibilityNodeInfo> covertToMap(AccessibilityNodeInfo fromNodeInfo) {
        Map<Integer, AccessibilityNodeInfo> nodeInfoMap = new LinkedHashMap<>();
        if (fromNodeInfo != null) {
            List<AccessibilityNodeInfo> accessibilityNodeInfoList = getAllChildNode(new ArrayList<>(), fromNodeInfo);
            // 处理当前节点的逻辑，例如打印节点的信息等
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                for (AccessibilityNodeInfo nodeInfo : accessibilityNodeInfoList) {
                    // 使用Objects.hash以增强哈希值的唯一性
                    int hashCode = Objects.hash(nodeInfo);
                    nodeInfoMap.put(hashCode, nodeInfo);
                }
            } else {
                for (AccessibilityNodeInfo nodeInfo : accessibilityNodeInfoList) {
                    // 使用Objects.hash以增强哈希值的唯一性
                    int hashCode = nodeInfo.hashCode();
                    nodeInfoMap.put(hashCode, nodeInfo);
                }
            }
        }
        return nodeInfoMap;
    }*/

    public enum ScreenPosition {
        IN_SCREEN,  // 屏幕内
        OUT_SCREEN, // 屏幕外
        NO_LIMIT, // 不限
    }

    public static class FindBuilder implements Cloneable {
        // 深度匹配参数，默认为 false
        boolean depthMatch = false;
        int clickable = -1;//0不可点击，1可点击
        int visible = NONE;//0可见，8不可见 -1不过滤
        AccessibilityNodeInfo anchorNodeInfo;//依赖参考锚点
        boolean matchingInSub;// true 匹配子节点，false 向父节点匹配
        ScreenPosition inScreenType = ScreenPosition.OUT_SCREEN;// ScreenPosition.IN_SCREEN;
        //AccessibilityNodeInfo uperNodeInfo;//查找这个节点上层的节点
        String text_regex;
        String text_equals;
        String contentDescription;
        String id;
        String viewClassName;
        boolean isList = false;
        int resultCount = 1;//1findone 2findlist

        public static FindBuilder get() {
            return new FindBuilder();
        }

        public FindBuilder setDepthMatch(boolean depthMatch) {
            this.depthMatch = depthMatch;
            return this;
        }

        public FindBuilder setResultCount(int resultCount) {
            this.resultCount = resultCount;
            return this;
        }

        /**
         * @param clickable 0不可点击，1可点击 -1不过滤
         * @return
         */
        public FindBuilder setClickable(int clickable) {
            this.clickable = clickable;
            return this;
        }

        public static final int NONE = -1;

        /**
         * @hide
         */
        @IntDef({VISIBLE, GONE, NONE})
        @Retention(RetentionPolicy.SOURCE)
        public @interface Visibility {
        }

        /**
         * @param visible 0可见，8不可见 -1不过滤
         * @return
         */
        public FindBuilder setVisible(@Visibility int visible) {
            this.visible = visible;
            return this;
        }

        public FindBuilder setInScreenType(ScreenPosition inScreenType) {
            this.inScreenType = inScreenType;
            return this;
        }

        public FindBuilder setViewClassName(String viewClassName) {
            this.viewClassName = viewClassName;
            return this;
        }

        public FindBuilder setId(String id) {
            this.id = id;
            return this;
        }

        public FindBuilder setText_equals(String text_equals) {
            this.text_equals = text_equals;
            return this;
        }

        public FindBuilder setText_regex(String text_regex) {
            this.text_regex = text_regex;
            return this;
        }

        public FindBuilder setAnchorNodeInfo(AccessibilityNodeInfo anchorNodeInfo) {
            this.anchorNodeInfo = anchorNodeInfo;
            return this;
        }

        public FindBuilder setAnchorNodeInfo(AccessibilityNodeInfo anchorNodeInfo, int level) {
            AccessibilityNodeInfo nodeInfo = anchorNodeInfo;
            for (int i = 0; i < Math.abs(level); i++) {
                nodeInfo = nodeInfo.getParent();
            }
            this.anchorNodeInfo = nodeInfo;
            return this;
        }

//        public FindBuilder setMatchingInSub(boolean matchingInSub) {
//            this.matchingInSub = matchingInSub;
//            return this;
//        }

        public FindBuilder setContentDescription(String contentDescription) {
            this.contentDescription = contentDescription;
            return this;
        }

        public AccessibilityNodeInfo findOne() {
            isList = false;
            long start = System.currentTimeMillis();
            List<AccessibilityNodeInfo> list = findOneByBuilder(this);
            if (list != null && list.size() > 0) {
                Rect rect = new Rect();
                AccessibilityNodeInfo nodeInfo = list.get(0);
                nodeInfo.getBoundsInScreen(rect);
                printLog(start, "查询耗时1:", nodeInfo + ",rect=" + rect + ",rect.width=" + rect.width() + ",rect.height=" + rect.height());
                return nodeInfo;
            }
            printLog(start, "查询耗时2:", null);
            return null;
        }

        private void printParent(AccessibilityNodeInfo accessibilityNodeInfo) {
            if (accessibilityNodeInfo != null && accessibilityNodeInfo.getParent() != null) {
                Rect rect = new Rect();
                accessibilityNodeInfo.getParent().getBoundsInScreen(rect);
                Log.i("findOneByBuilder", "parent:" + rect + "," + accessibilityNodeInfo);
                printParent(accessibilityNodeInfo.getParent());
            }
        }

        private void printLog(long start, String method, String body) {
            StringBuilder logMessage = new StringBuilder(method);
            long useTime = System.currentTimeMillis() - start;
            if (useTime > 5000) {
                logMessage.append(useTime).append("ms");


                if (!TextUtils.isEmpty(id)) {
                    logMessage.append(", ID: ").append(id);
                }

                if (!TextUtils.isEmpty(text_equals)) {
                    logMessage.append(", 文本1: ").append(text_equals);
                }

                if (!TextUtils.isEmpty(text_regex)) {
                    logMessage.append(", 文本2: ").append(text_regex);
                }

                if (!TextUtils.isEmpty(contentDescription)) {
                    logMessage.append(", 描述: ").append(contentDescription);
                }
                logMessage.append(", 显示: ").append(visible + "");

//            if(findBuilder.text_equals.equals("发表评论后参与")) {
//                Log.i("findOneByBuilder", "nodeInfo.getText():" + nodeInfo.getText());
//            }

                Log.e("AccessNodeFinder", logMessage.toString() + "," + body);
            }
        }

        public List<AccessibilityNodeInfo> findList() {
            isList = true;
            return findOneByBuilder(this);
        }

        @NonNull
        @Override
        public Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }

}
